package mfgrep;

import java.io.File;
import java.io.IOException;
import java.util.Map;
import java.util.Map.Entry;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Pattern;
import java.util.jar.*;
import java.util.regex.Matcher;
import java.util.zip.ZipException;

/**
 * Grepper. Dedicated to grepfruit :-)
 * 
 * Works hardly - extracts the information from files.
 * 
 * Class is NOT thread safe!
 * 
 * @author lzapletal
 */
public class Grepper implements FileProcessor {

  private static Logger logger = Logger.getAnonymousLogger();
  private String pattern;
  private Pattern regexPattern;
  private ProgramOptions programOptions;

  public Grepper(String pattern, ProgramOptions programOptions) {
	if (pattern == null || pattern.length() == 0) {
	  throw new IllegalArgumentException("Pattern cannot be null or empty");
	}
	if (programOptions == null) {
	  throw new IllegalArgumentException("Program options cannot be null");
	}
	this.pattern = pattern;
	this.programOptions = programOptions;
	int flags = 0;
	if (!programOptions.isCaseSensitive()) {
	  flags |= Pattern.CASE_INSENSITIVE;
	}
	regexPattern = Pattern.compile(pattern, flags);
  }

  private static void printEntry(Object key, Object value, File file) {
	System.out.print(key);
	System.out.print(": ");
	System.out.print(value);
	System.out.print(" (");
	System.out.print(file);
	System.out.println(")");
  }

  private void printAttributes(Attributes attributes, File file) {
	for (Entry entry : attributes.entrySet()) {
	  String key = entry.getKey().toString();
	  Matcher matcher = regexPattern.matcher(key);
	  if (matcher.find()) {
		printEntry(entry.getKey(), entry.getValue(), file);
	  }
	}
  }

  public void acceptFile(File file) throws ProcessingException {
	// check if the extension match
	String fileName = file.getName();
	if (fileName.length() < 3)
		return; // skipping
	String extension = fileName.substring(fileName.length() - 3, fileName.length());
	if (!programOptions.hasExtension(extension)) {
	  return; // skipping

	// process the file
	}
	logger.fine("Processing file " + file);
	Map<String, Attributes> entries;
	try {
	  JarFile jarFile = new JarFile(file, false);
	  Manifest manifest = jarFile.getManifest();
	  if (manifest == null) {
		logger.finer("Manifest for file " + file + " is empty");
		return;
	  }
	  // read main attributes
	  printAttributes(manifest.getMainAttributes(), file);
	  // read sub-attributes
	  entries = manifest.getEntries();
	  for (String key : entries.keySet()) {
		printAttributes(entries.get(key), file);
	  }
	// done reading with this file
	} catch (ZipException ex) {
	  logger.warning("Error when reading file " + file + ": " + ex.getMessage());
	} catch (Exception ex) {
	  throw new ProcessingException("Error while processing file " + file, ex);
	}
  }
}
